#!/usr/bin/env python2
# -*- coding: utf-8 -*-

"""
Brief  : 文字生成器弹窗，大量移植了主程序中的操作
Author : 傅帅
Date   : 2020.7.21
Warn   : 为方便移植主程序中的各种操作，本窗口未写成类的形式，故一次仅可开启一个窗口
"""
import os
import re
import sys
import copy
import json
import Tkinter as tk
import tkFont
import tkFileDialog
import tkMessageBox
import numpy as np
from Tkinter import NW
from PIL import Image, ImageTk

reload(sys)
sys.setdefaultencoding('utf8')

# 控件
root = None
canvas = None
canvas_menu = None
name_entry = None
loaded_font_name = ''
scale_window = None
scale_entry = None
resize_scale = 1.0
# 字体
black12 = None
black14 = None
black16 = None
# 杂七杂八
pics = []  # 这个用于存储最后用于画在canvas上的PhotoImage类型的对象，防止其作为局部变量被回收
canvas_mouse_state = 'up'  # 'up'/'select'/'drag'
canvas_mouse_down_pos = [] # 鼠标左键按下时的坐标
choose_box_canvas_id = -1 # 选择框的canvas_id
selected_canvas_ids = []  # 存储当前选择的对象的canvas_id
canvas_ctrl_down = False  # 标记左键抬起时是否按下了Ctrl
drag_box_canvas_ids = []  # 存储拖动框的canvas_id
current_strokes = [       # 表示文字中所有笔画的尺寸信息[mm]
    # {
    #     'name':'',
    #     'position':[x,y],
    #     'rectangle_size':[x,y],
    #     'canvas_id':id
    # },
    # {
    #     ...
    # }
]
current_strokes_pix = []  # 结构与上相同，表示文字中所有笔画的像素信息[pix]
font_size = [0, 0]  # 文字尺寸[mm]
pix_scale = 1           # 表示mm到像素的缩放比例 mm*pix_scale=像素
# 超参数
BORDER_SIZE = 2  # 选中框的宽度
CANVAS_SIZE = 500.0

def OpenFontCreator(father):
    '''开启文字生成器窗口'''
    global root, canvas, canva_menu, black12, black14, black16
    if root != None: 
        father.destroy()
        tkMessageBox.showinfo("已启动","请勿重复开启文字生成器!")
        return
    root = father
    canvas = tk.Canvas()
    canvas_menu = tk.Menu()
    black12 = tkFont.Font(root, family="黑体", size=12)
    black14 = tkFont.Font(root, family="黑体", size=14)
    black16 = tkFont.Font(root, family="黑体", size=16)
    root.resizable(width = False, height = False)
    GUI_Init()

def GUI_Init():
    global root, canvas, canvas_menu
    root.geometry("525x525")
    root.title('文字创建[当前文字尺寸:0.00mm x 0.00mm]')
    # ---------------------------------- 菜单 ----------------------------------------
    topmenu = tk.Menu(root, font=black16)
    topmenu.add_command(label="加入笔画", command=AddStroke)
    topmenu.add_command(label="保存文字", command=SaveFont)
    topmenu.add_command(label="导入文字", command=LoadFont)
    topmenu.add_command(label="缩放文字", command=ScaleFont)
    # 将topmenu设置为顶部菜单
    root.config(menu=topmenu)
    # ---------------------------------- 画布 ----------------------------------------
    # 创建画布
    canvas = tk.Canvas(root, bg = "#FFFFFF", width = CANVAS_SIZE, height = CANVAS_SIZE)
    canvas.place(x=10, y=10)
    canvas_menu = tk.Menu()
    # 绑定鼠标事件
    canvas.bind('<Button-1>', onCanvasLeftButtonDown)
    canvas.bind('<B1-Motion>', onCanvasLeftButtonMove)
    canvas.bind('<ButtonRelease-1>', onCanvasLeftButtonUp)
    canvas.bind('<ButtonRelease-3>', onCanvasRightButtonUp)
    canvas.bind("<Control-ButtonRelease-1>", onCtrlCanvasLeftButtonUp)
    # 画布下的菜单
    canvas_menu = tk.Menu(canvas, tearoff=0)
    canvas_menu.add_command(label='删除所选笔画', command=DeleteSelectionBtnCb, font=black14)
    canvas_menu.add_command(label='清空全部笔画', command=ClearWorkspaceBtnCb, font=black14)
    # ---------------------------------- 启动 ----------------------------------------
    root.protocol("WM_DELETE_WINDOW", OnClose)  # 注册关闭事件

def OnClose():
    global root
    root.destroy()
    root = None

def AddStroke():
    '''弹出窗口,添加笔画'''
    add_stroke_window = tk.Toplevel()
    AddStrokeWindow(add_stroke_window)

def SaveFont():
    global name_entry
    if len(current_strokes) == 0:
        tkMessageBox.showinfo("保存失败","工作区内无笔画", parent=root)
        return
    window = tk.Toplevel(root)
    window.bind("<Return>", OnSaveWindowEnter)
    window.bind("<Escape>", OnSaveWindowEsc)
    window.geometry('270x60+{}+{}'.format(root.winfo_x()+120, root.winfo_y()+190))
    window.title("请输入文字名称")
    name_entry = tk.Entry(window, width='16', font=black12)
    name_entry.place(x=15, y=20)
    name_entry.insert(0, loaded_font_name)
    submit_btn = tk.Button(window, text='保存文字', command=SaveBtnCb, font=black12)
    submit_btn.place(x=170, y=15)

def OnSaveWindowEnter(event):
    SaveBtnCb()

def OnSaveWindowEsc(event):
    event.widget.destroy()

def SaveBtnCb():
    save_font_name = name_entry.get()
    if save_font_name == '':
        tkMessageBox.showinfo("保存失败","文件名不可为空", parent=root)
        return
    strokes = []
    for item in current_strokes:
        # 按resize_scale修改笔画尺寸和offset后加入strokes
        _ResizeStroke(item['name'])
        scaled_position = [item['position'][0]*resize_scale, item['position'][1]*resize_scale]
        strokes.append({'stroke_name':item['name'], 'stroke_offset':scaled_position})
    if not os.path.exists('calligraphy_lib/fonts'): os.makedirs('calligraphy_lib/fonts')
    with open('./calligraphy_lib/fonts/'+save_font_name+'.json', 'w') as f:
        scaled_font_size = [font_size[0]*resize_scale, font_size[1]*resize_scale]
        json_str = json.dumps({'font_name':save_font_name, 'font_size':scaled_font_size,'strokes': strokes}, indent=4, ensure_ascii=False)
        f.write(json_str)
    # 存图片
    _font_size = [int(font_size[0]*resize_scale), int(font_size[1]*resize_scale)]
    target_pic = Image.new('RGBA', _font_size)
    for item in current_strokes:
        scaled_rectangle_size = [int(item['rectangle_size'][0]*resize_scale), int(item['rectangle_size'][1]*resize_scale)]
        stroke_pic = Image.open('./calligraphy_lib/strokes/'+item['name']+'.png').resize(scaled_rectangle_size)
        stroke_pic = stroke_pic.convert('RGBA')
        r,g,b,a = stroke_pic.split()
        target_pic.paste(stroke_pic, tuple([int(item['position'][0]*resize_scale),int(item['position'][1]*resize_scale)]), mask=a)
    target_pic.save('./calligraphy_lib/fonts/'+save_font_name+'.png')
    tkMessageBox.showinfo("保存成功","已成功保存文字"+save_font_name+"到字库!", parent=root)

def _ResizeStroke(stroke_name):
    stroke_obj = None
    with open('./calligraphy_lib/strokes/'+stroke_name+'.json', 'r') as f:
        stroke_obj = json.loads(f.read())
        stroke_obj['stroke_size'] = [stroke_obj['stroke_size'][0]*resize_scale,stroke_obj['stroke_size'][1]*resize_scale]
        for i in range(len(stroke_obj['stroke_points'])):
            stroke_obj['stroke_points'][i][0] = stroke_obj['stroke_points'][i][0]*resize_scale
            stroke_obj['stroke_points'][i][1] = stroke_obj['stroke_points'][i][1]*resize_scale
    with open('./calligraphy_lib/strokes/'+stroke_name+'.json', 'w') as f:
        f.write(json.dumps(stroke_obj, indent=4, ensure_ascii=False))
        

def LoadFont():
    global font_size, current_strokes, loaded_font_name
    path = tkFileDialog.askopenfilename(title='导入文字', filetypes=[('文字参数文件', '*.json')])
    if path == '' or path == (): return
    with open(path, 'r') as f:
        font_obj = json.loads(f.read())
    font_size = font_obj['font_size']
    current_strokes = []
    for stroke in font_obj['strokes']:
        stroke_obj = json.loads(open('./calligraphy_lib/strokes/'+stroke['stroke_name']+'.json','r').read())
        foo = {
            'name':stroke['stroke_name'],
            'position':stroke['stroke_offset'],
            'rectangle_size':[stroke_obj['stroke_size'][0], stroke_obj['stroke_size'][1]],
        }
        current_strokes.append(foo)
    loaded_font_name = font_obj['font_name']
    UpdateCanvas()

def ScaleFont():
    global scale_window,scale_entry
    scale_window = tk.Toplevel(root)
    scale_window.bind("<Return>", OnScaleWindowEnter)
    scale_window.bind("<Escape>", OnScaleWindowEsc)
    scale_window.geometry('270x60+{}+{}'.format(root.winfo_x()+120, root.winfo_y()+190))
    scale_window.title("请输入缩放比例[百分制]")
    scale_entry = tk.Entry(scale_window, width='16', font=black12)
    scale_entry.place(x=15, y=20)
    scale_entry.insert(0, 100.0)
    submit_btn = tk.Button(scale_window, text='缩放文字', command=ScaleBtnCb, font=black12)
    submit_btn.place(x=170, y=15)

def OnScaleWindowEnter(event):
    ScaleBtnCb()

def OnScaleWindowEsc(event):
    event.widget.destroy()

def ScaleBtnCb():
    global resize_scale
    scale_str = scale_entry.get()
    if(re.match('^[0-9]+$|^[0-9]+\.[0-9]*$', scale_str) == None):
        tkMessageBox.showinfo("错误","请输入正确的百分制缩放倍率!", parent=scale_window)
        return
    resize_scale = float(scale_str)/100.0
    scale_window.destroy()
    tkMessageBox.showinfo("请注意！","修改缩放倍率后\n保存时会直接修改笔画文件中的尺寸！！！", parent=root)
    UpdateCanvas()

def onCanvasLeftButtonDown(event):
    global canvas_mouse_state,canvas_mouse_down_pos
    canvas_mouse_down_pos = [event.x, event.y]
    canvas_menu.unpost()
    # 根据按下位置是否在已选中范围内判断select or drag
    for canvas_id in selected_canvas_ids:  # 遍历已选中对象
        for item in current_strokes_pix:  # 获取该canvas_id的对象
            if item['canvas_id'] == canvas_id:
                break
        if _AInBRange([event.x, event.y], item['position'], item['rectangle_size']):
            # 若检测到按键位置处于任意一个已选中范围内,鼠标状态设置为拖动
            canvas_mouse_state = 'drag'
            return
    # 若不在任意一个已选中范围内，则为选择
    canvas_mouse_state = 'select'

def onCanvasLeftButtonMove(event):
    global choose_box_canvas_id
    if canvas_mouse_state == 'select':
        if choose_box_canvas_id != -1:canvas.delete(choose_box_canvas_id)
        choose_box_canvas_id = canvas.create_rectangle(canvas_mouse_down_pos[0], canvas_mouse_down_pos[1],
            event.x, event.y)
    elif canvas_mouse_state == 'drag':
        global drag_box_canvas_ids
        deltaX = event.x - canvas_mouse_down_pos[0]
        deltaY = event.y - canvas_mouse_down_pos[1]
        # 清空拖动框
        for canvas_id in drag_box_canvas_ids:
            canvas.delete(canvas_id)
        # 更新拖动框位置
        for canvas_id in selected_canvas_ids:
            # 遍历找到该canvas_id对应的对象item
            for item in current_strokes_pix:
                if item['canvas_id'] == canvas_id:
                    break
            posNW = [item['position'][0] + deltaX,
                    item['position'][1] + deltaY]
            posSE = [item['position'][0] + item['rectangle_size'][0] + deltaX,
                     item['position'][1] + item['rectangle_size'][1] + deltaY]
            foo = canvas.create_rectangle(posNW[0]-BORDER_SIZE, posNW[1]-BORDER_SIZE,
                posSE[0]+BORDER_SIZE, posSE[1]+BORDER_SIZE, outline='green', width=BORDER_SIZE)
            drag_box_canvas_ids.append(foo)

# 按下Ctrl时可添加选中项
def onCtrlCanvasLeftButtonUp(event):
    global canvas_ctrl_down
    canvas_ctrl_down = True
    onCanvasLeftButtonUp(event)

def onCanvasLeftButtonUp(event):
    global canvas_mouse_state, selected_canvas_ids, canvas_ctrl_down
    if event.x == canvas_mouse_down_pos[0] and event.y == canvas_mouse_down_pos[1]:  # 若为点击,则一定为为选择
        canvas_mouse_state = 'select'
    # 动作为选择
    if canvas_mouse_state == 'select':
        if not canvas_ctrl_down: selected_canvas_ids = []
        # 根据框选或点击情况更新selected_canvas_ids
        # 选择方式为点击
        if abs(event.x-canvas_mouse_down_pos[0])<10 and abs(event.y-canvas_mouse_down_pos[1])<10:
            current_strokes_pix.reverse()  # 翻转
            for item in current_strokes_pix:  # 从后到前遍历寻找最上层的对象
                if _AInBRange([event.x, event.y], item['position'], item['rectangle_size']):
                    if item['canvas_id'] not in selected_canvas_ids:
                        selected_canvas_ids.append(item['canvas_id'])
                    else:
                        selected_canvas_ids.remove(item['canvas_id'])
                    break
            current_strokes_pix.reverse()  # 翻转
        # 选择方式为框选
        else:
            if choose_box_canvas_id != -1:canvas.delete(choose_box_canvas_id)  # 删除框选框
            for item in current_strokes_pix:  # 遍历寻找框内对象
                P_NW = item['position']
                P_SE = [item['position'][0] + item['rectangle_size'][0],
                        item['position'][1] + item['rectangle_size'][1]]
                # 两种情况，向右下拉或向左上拉
                # 向右下拉
                if event.x >= canvas_mouse_down_pos[0] and event.y >= canvas_mouse_down_pos[1]:
                    select_box_rectangle = [event.x - canvas_mouse_down_pos[0],
                                            event.y - canvas_mouse_down_pos[1]]
                    # 若对象完全在框选范围内
                    if _AInBRange(P_NW, canvas_mouse_down_pos, select_box_rectangle) and \
                       _AInBRange(P_SE, canvas_mouse_down_pos, select_box_rectangle):
                        if item['canvas_id'] not in selected_canvas_ids:
                            selected_canvas_ids.append(item['canvas_id'])
                # 向左上拉
                else:
                    # 选框左上在目标右下的左上，且选框右下在目标左上的右下
                    if event.x < item['position'][0] + item['rectangle_size'][0] and \
                       event.y < item['position'][1] + item['rectangle_size'][1] and \
                       canvas_mouse_down_pos[0] > item['position'][0] and \
                       canvas_mouse_down_pos[1] > item['position'][1]:
                        if item['canvas_id'] not in selected_canvas_ids:
                            selected_canvas_ids.append(item['canvas_id'])
    # 动作为拖动
    elif canvas_mouse_state == 'drag':
        deltaX = event.x - canvas_mouse_down_pos[0]
        deltaY = event.y - canvas_mouse_down_pos[1]
        # 对于被选中项,更改current_strokes中的position
        for canvas_id in selected_canvas_ids:
            # 遍历找到该canvas_id对应的对象item
            for item in current_strokes:
                if item['canvas_id'] == canvas_id:
                    break
            item['position'] = [
                item['position'][0] + deltaX/pix_scale,
                item['position'][1] + deltaY/pix_scale
            ]
    canvas_mouse_state = 'up'
    canvas_ctrl_down = False
    UpdateCanvas()

def onCanvasRightButtonUp(event):
    canvas_menu.post(event.x_root, event.y_root) 

def UpdateCanvas():
    '''根据current_strokes计算更新字体尺寸和current_strokes_pix，并根据selected_canvas_ids更新选中情况'''
    global root, canvas, pics, selected_canvas_ids, font_size, pix_scale, current_strokes, current_strokes_pix
    canvas.delete('all')
    if len(current_strokes) == 0: 
        font_size = [0, 0]
        root.title("文字创建[当前文字尺寸:{:.2f}mm x {:.2f}mm]".format(font_size[0], font_size[1]))
        return  # 无笔画则不需进行后续动作
    pics = []  # 这个全局变量只是为了保证PhotoImage不被回收
    # 根据最小外接矩形裁剪文字，然后缩放至画布并设置缩放系数
    x0,y0,x1,y1 = 10000,10000,0,0  # 记录左上右下脚点
    for item in current_strokes:
        if item['position'][0] < x0: x0 = item['position'][0]
        if item['position'][1] < y0: y0 = item['position'][1]
        if item['position'][0]+item['rectangle_size'][0] > x1: x1 = item['position'][0]+item['rectangle_size'][0]
        if item['position'][1]+item['rectangle_size'][1] > y1: y1 = item['position'][1]+item['rectangle_size'][1]
    for item in current_strokes:  # 裁剪文字
        item['position'][0] -= x0
        item['position'][1] -= y0
    font_size = [x1-x0, y1-y0]
    root.title("文字创建[当前文字尺寸:{:.2f}mm x {:.2f}mm]".format(font_size[0]*resize_scale, font_size[1]*resize_scale))
    # 更新pix_scale和current_strokes_pix
    current_strokes_pix = copy.deepcopy(current_strokes)
    if font_size[0] > font_size[1]:  # x方向更长
        pix_scale = CANVAS_SIZE/font_size[0]
        offset = [0, int((CANVAS_SIZE - font_size[1]*pix_scale)/2)]
    else:
        pix_scale = CANVAS_SIZE/font_size[1]
        offset = [int((CANVAS_SIZE - font_size[0]*pix_scale)/2), 0]
    for item in current_strokes_pix:
        item['position'][0] = int(item['position'][0]*pix_scale) + offset[0]
        item['position'][1] = int(item['position'][1]*pix_scale) + offset[1]
        item['rectangle_size'][0] = int(item['rectangle_size'][0]*pix_scale)
        item['rectangle_size'][1] = int(item['rectangle_size'][1]*pix_scale)
    # 在画布中更新每一个笔画
    canvas.create_rectangle(offset[0], offset[1], offset[0]+font_size[0]*pix_scale, offset[1]+font_size[1]*pix_scale,
        outline='white', fill='#AAAAAA')  # 背景
    for index,item in enumerate(current_strokes_pix):
        posNW = item['position']
        posSE = [item['position'][0]+item['rectangle_size'][0], 
                 item['position'][1]+item['rectangle_size'][1]]
        # 判断是否被选中
        if_selected = False
        item.setdefault('canvas_id',-1)
        if item['canvas_id'] in selected_canvas_ids:
            if_selected = True
            BORDER_SIZE = 2
            canvas.create_rectangle(posNW[0]-BORDER_SIZE, posNW[1]-BORDER_SIZE,
                posSE[0]+BORDER_SIZE, posSE[1]+BORDER_SIZE, outline='blue', width=BORDER_SIZE)
            selected_canvas_ids.remove(item['canvas_id'])  # 删掉旧的准备换新的
        # 画对象本身
        pic_org = Image.open('./calligraphy_lib/strokes/'+item['name']+'.png')
        pic_resized = pic_org.resize((item['rectangle_size'][0], item['rectangle_size'][1]), Image.ANTIALIAS)  # 缩放
        pic = ImageTk.PhotoImage(pic_resized)
        pics.append(pic)
        # 新的canvas_id
        item['canvas_id'] = canvas.create_image(int(item['position'][0]), int(item['position'][1]), anchor=NW, image = pic)
        current_strokes[index]['canvas_id'] = item['canvas_id']
        # 若之前被选中，重画后更新一下canvas_id
        if if_selected: selected_canvas_ids.append(item['canvas_id'])

def DeleteSelectionBtnCb():
    global current_strokes, selected_canvas_ids
    '''从current_strokes中删除掉selected_canvas_ids'''
    delete_list = []
    for index, item in enumerate(current_strokes):
        if item['canvas_id'] in selected_canvas_ids:
            delete_list.append(index)
    delete_list.reverse()  # 从后往前删
    for index in delete_list:
        current_strokes.pop(index)
    selected_canvas_ids = []
    UpdateCanvas()

def ClearWorkspaceBtnCb():
    global current_strokes, selected_canvas_ids
    current_strokes = []
    selected_canvas_ids = []
    UpdateCanvas()

def _AInBRange(A=[0,0], B_NW=[0,0], B_rectangle=[1,1]):
    if B_NW[0] < A[0] and A[0] < B_NW[0] + B_rectangle[0] and \
       B_NW[1] < A[1] and A[1] < B_NW[1] + B_rectangle[1]:
        return True
    else:
        return False

class AddStrokeWindow():
    '''用于向工作空间添加笔画的弹窗'''
    def __init__(self, root):
        self.root = root
        self.LABEL_BG = 180.0  # pix 背景矩形尺寸
        self.LABEL_SIZE = 160.0  # 笔画预览尺寸
        self.LABEL_LINE_GAP = 40.0  # 两行间放名称的间隔行长度
        self.X_GAP = 200  # X方向一个对象的占位
        self.X_PADDING = int(self.X_GAP-self.LABEL_BG)/2  # X方向背景在占位两侧的padding
        self.Y_GAP = int(self.LABEL_BG+self.LABEL_LINE_GAP)  # X方向一个对象的占位
        self.chosen_index = None  # 一次选择的对象下标，再次点击则表示添加
        self.search_entry = None
        self.frame = tk.Frame
        self.items_name_list_total = []  # 所有item的名称list
        self.items_name_list = []  # 需要展示item的名称list
        self.label_list = []
        self.pic_list = []  # 这个用于存储最后用于画在canvas上的PhotoImage类型的对象，防止其作为局部变量被回收，canvas画img的大坑-_-|
        pic1 = Image.open('./misc/unselected.png')  
        pic2 = Image.open('./misc/selected.png')  
        self.unselected_img = ImageTk.PhotoImage(pic1)
        self.selected_img = ImageTk.PhotoImage(pic2)
        self.ReadItems()
        self.GUI_Init()
    
    def ReadItems(self):
        '''读取strokes下的预览图名称,存入self.items_name_list'''
        file_list = os.listdir('./calligraphy_lib/strokes')
        for f_name in file_list:
            if re.search('.\.png', f_name) != None:
                self.items_name_list_total.append(f_name[:-4].decode('utf-8'))
        self.items_name_list_total.sort()  # 字节序排序
        self.items_name_list = self.items_name_list_total

    def GUI_Init(self):
        self.root.geometry("1000x940")
        title = '点击添加笔画(请点击笔画本身而非背景)'
        self.root.title(title)
        self.root.bind('<Button-1>', self.OnLeftButtonDown)  # 用于判断选取的对象
        self.root.bind("<Return>", self.OnEnter)
        self.root.bind("<Escape>", self.OnEsc)
        # 搜索框
        tk.Label(self.root, text="搜索:", font=black12, fg='black').place(x=370, y=10)
        self.search_entry = tk.Entry(self.root, width='10', font=black12)
        self.search_entry.place(x=415, y=10)
        tk.Button(self.root, text="搜索", command=self.SearchCb, font=black12).place(x=525, y=5)
        self.UpdatePics()
    
    def UpdatePics(self):
        self.frame = tk.Frame(self.root)
        self.frame['width'] = 1000
        self.frame['height'] = 880
        self.frame.place(x=0, y=50)
        # 读取需要展示的预览图并渲染为label
        for index,name in enumerate(self.items_name_list):
            if index>=20: return  # 只显示前20个
            path = './calligraphy_lib/strokes/'+name+'.png'
            pic_org = Image.open(path)  
            # 图片尺寸缩放
            resizeX = self.LABEL_SIZE
            resizeY = self.LABEL_SIZE
            if pic_org.height > pic_org.width:  # Y轴较长
                scale = self.LABEL_SIZE/pic_org.height
                resizeX = scale * pic_org.width
            else:  # X轴较长
                scale = self.LABEL_SIZE/pic_org.width
                resizeY = scale * pic_org.height
            pic_resized = pic_org.resize((int(resizeX), int(resizeY)), Image.ANTIALIAS)  # 缩放至预设尺寸
            self.pic_list.append(ImageTk.PhotoImage(pic_resized))
            # 预览图的排布
            x_index = index%5
            y_index = index/5
            tk.Label(self.frame, image=self.unselected_img).place(x=x_index*self.X_GAP+self.X_PADDING, y=y_index*self.Y_GAP)
            self.label_list.append(tk.Label(self.frame, image=self.pic_list[index]))
            if pic_org.height > pic_org.width:  # Y轴较长,X方向居中
                self.label_list[index].place(x=x_index*self.X_GAP+int((self.LABEL_BG-resizeX)/2), y=y_index*self.Y_GAP+10)
            else:  # X轴较长,Y方向居中
                self.label_list[index].place(x=x_index*self.X_GAP+20, y=y_index*self.Y_GAP+int((self.LABEL_BG-resizeY)/2))
            name = self.items_name_list[index]
            x_offset = self.X_GAP/2-len(name)*9
            tk.Label(self.frame, text=name, font=black14).place(x=x_index*self.X_GAP+x_offset, y=y_index*self.Y_GAP+182)
    
    def SearchCb(self):
        search_str = self.search_entry.get()
        self.items_name_list = []
        self.label_list = []
        self.pic_list = []
        self.chosen_index = None
        self.frame.destroy()
        for name in self.items_name_list_total:
            if re.search(search_str, name) != None:
                self.items_name_list.append(name)
        self.UpdatePics()
    
    def OnEnter(self, event):
        self.SearchCb()

    def OnEsc(self, event):
        self.root.destroy()
    
    def OnLeftButtonDown(self, event):
        global current_strokes,canvas
        # 获取当前点击的对象
        index = None
        if event.widget.widgetName != 'label':
            return
        else:
            for i,item in enumerate(self.label_list):
                if item == event.widget:
                    index = i
                    break
        if index == None:return  # 点到了背景图，而不是对象图本身
        if self.chosen_index != index:  # 点了新的
            # 恢复旧的对象背景图
            if self.chosen_index != None:  # 第一次点击不需更新
                old_index = self.chosen_index
                x_index = old_index%5
                y_index = old_index/5
                tk.Label(self.frame, image=self.unselected_img).place(x=x_index*self.X_GAP+self.X_PADDING, y=y_index*self.Y_GAP)
                pic_size = self.pic_list[old_index]._PhotoImage__size
                # 创建一个新的Label,防止旧Label被覆盖
                self.label_list[old_index].destroy()
                self.label_list[old_index] = tk.Label(self.frame, image=self.pic_list[old_index])
                if pic_size[1] > pic_size[0]:  # Y轴较长,X方向居中
                    self.label_list[old_index].place(x=x_index*self.X_GAP+int((self.LABEL_BG-pic_size[0])/2), y=y_index*self.Y_GAP+10)
                else:  # X轴较长,Y方向居中
                    self.label_list[old_index].place(x=x_index*self.X_GAP+20, y=y_index*self.Y_GAP+int((self.LABEL_BG-pic_size[1])/2))
            # 更新新的对象背景图
            self.chosen_index = index
            x_index = index%5
            y_index = index/5
            tk.Label(self.frame, image=self.selected_img).place(x=x_index*self.X_GAP+self.X_PADDING, y=y_index*self.Y_GAP)
            pic_size = self.pic_list[index]._PhotoImage__size
            self.label_list[index].destroy()
            self.label_list[index] = tk.Label(self.frame, image=self.pic_list[index])
            if pic_size[1] > pic_size[0]:  # Y轴较长,X方向居中
                self.label_list[index].place(x=x_index*self.X_GAP+int((self.LABEL_BG-pic_size[0])/2), y=y_index*self.Y_GAP+10)
            else:  # X轴较长,Y方向居中
                self.label_list[index].place(x=x_index*self.X_GAP+20, y=y_index*self.Y_GAP+int((self.LABEL_BG-pic_size[1])/2))
        else:
            # 将笔画加入画布,更新current_strokes
            name = self.items_name_list[self.chosen_index]
            obj = json.loads(open('./calligraphy_lib/strokes/'+name+'.json','r').read())
            rectangle_size = obj['stroke_size']
            foo = {
                'name':name,
                'position':[(font_size[0]-rectangle_size[0])/2, (font_size[1]-rectangle_size[1])/2],
                'rectangle_size':[rectangle_size[0],rectangle_size[1]],
            }
            current_strokes.append(foo)
            UpdateCanvas()

if __name__ == "__main__":
    foo = tk.Tk()
    OpenFontCreator(foo)
    foo.mainloop()
    
